﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using SimpleServiceBus.Bus.MessageManagement;
using SimpleServiceBus.Utilities;

namespace SimpleServiceBus.Bus.Subscriptions
{
    [Serializable]
    public class MessageTypeSubscription : ISubscription
    {
        private readonly MessageTypePredicate _predicate;
        private readonly Dictionary<string,string> _subscribers;
        
        [NonSerialized]
        private ReaderWriterLock _rwLock = new ReaderWriterLock();

        public MessageTypeSubscription(Type messageType,params string[] subscribers)
        {
            _predicate = new MessageTypePredicate { MessageType = messageType };
            _subscribers = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);

            AddSubscribers(subscribers);
        }

        public bool Matches(MessageEnvelope messageEnvelope)
        {
            return _predicate.Matches(messageEnvelope);
        }

        public Type MessageType { get { return _predicate.MessageType; } }

        public string[] Subscribers
        {
            get
            {
                using (new ReaderLock(_rwLock,TimeSpan.FromSeconds(10)))
                {
                    return _subscribers.Keys.ToArray();
                }
            }
        }

        public void AddSubscribers(params string[] subscribers)
        {
            if (subscribers == null || subscribers.Length < 1)
                return;

            using (new WriterLock(_rwLock,TimeSpan.FromSeconds(10)))
            {
                foreach (string subscriber in subscribers)
                {
                    if (!_subscribers.ContainsKey(subscriber))
                        _subscribers.Add(subscriber, null);
                }
            }
        }

        public void RemoveSubscribers(params string[] subscribers)
        {
            if (subscribers == null || subscribers.Length < 1)
                return;

            using (new WriterLock(_rwLock,TimeSpan.FromSeconds(10)))
            {
                foreach (string subscriber in subscribers)
                    _subscribers.Remove(subscriber);
            }
        }
    }
}
